package br3akr.DeadlyDinnerParty.Server.Actions;

import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;

import br3akr.DeadlyDinnerParty.Server.Engine.Server;
import br3akr.DeadlyDinnerParty.Server.Engine.Session;
import br3akr.DeadlyDinnerParty.Server.Exceptions.DeadlyDinnerPartyException;
import br3akr.DeadlyDinnerParty.Server.World.Area;
import br3akr.DeadlyDinnerParty.Server.World.Body;
import br3akr.DeadlyDinnerParty.Server.World.GameCharacter;
import br3akr.DeadlyDinnerParty.Server.World.Ghost;
import br3akr.DeadlyDinnerParty.Server.World.Weapon;

public class AttackAction extends Action {
	private ActionResponse actionResponse;
	public static final Set<String> keywords;
	static {
		Set<String> tempKeywords = new HashSet<String>();
		tempKeywords.add("Attack");
		tempKeywords.add("At");
		keywords = Collections.unmodifiableSet(tempKeywords);
	}

	public AttackAction() {
		super("Attack", false);
	}

	public ActionResponse doAction(String action, Session session) throws DeadlyDinnerPartyException {
		if (action == null) {
			throw new DeadlyDinnerPartyException ("No action found.");
		}
		if (session == null) {
			throw new DeadlyDinnerPartyException ("No session found.");
		}
		StringTokenizer tokenizedAction = new StringTokenizer(action);
		String keyword = tokenizedAction.nextToken();
		String param1 = null;
		
		if (tokenizedAction.hasMoreTokens()) {
			param1 = tokenizedAction.nextToken();
		}
		
		if (param1 == null) {
			throw new DeadlyDinnerPartyException ("Who do you want to attack?");
		}
		
		GameCharacter actor = session.getCharacter();
		
		if (actor == null) {
			throw new DeadlyDinnerPartyException ("No character found for your session.");
		}
		
		if (actor.isRecovering()) {
			throw new DeadlyDinnerPartyException ("You can not attack while recovering.");
		}
		
		if (actor.getStatus() == GameCharacter.Status.INCAPACITATED) {
			throw new DeadlyDinnerPartyException ("You can not attack while incapacitated.");
		}
		
		actionResponse = new ActionResponse();
		actionResponse.setActingCharacter(actor);
		Area location = session.getCharacter().getLocation();
		
		switch (keyword.toLowerCase()) {
		case "attack":
		case "at":
			GameCharacter defender = location.getCharacter(param1);

			if (defender != null && !defender.isHiddenFrom(actor)) {
				actionResponse.setActingCharacter(actor);
				Random r = new Random();
				int roll = r.nextInt(100) + 1;
				actionResponse.addAffectedArea(location);
				StringBuilder atDesc = new StringBuilder();
				StringBuilder defDesc = new StringBuilder();
				StringBuilder onDesc = new StringBuilder();
				String hisHerText = (actor.getGender() == GameCharacter.Gender.MALE) ? "his" : "her";
				String himHerText = (actor.getGender() == GameCharacter.Gender.MALE) ? "him" : "her";
				String heSheText = (actor.getGender() == GameCharacter.Gender.MALE) ? "he" : "she";
				String hesShesText = (actor.getGender() == GameCharacter.Gender.MALE) ? "he's" : "she's";
				
				if (actor.getHeldItem() instanceof Weapon) {
					Weapon weapon = (Weapon)actor.getHeldItem();
					
					String hitMissText;
					
					String attackerHitMissText;
					if (roll >= 1) {
						defender.setDying(true);
						if (defender.getStatus() == GameCharacter.Status.HEALTHY) {
							defender.setStatus(GameCharacter.Status.INCAPACITATED);
						} else {
							defender.setStatus(GameCharacter.Status.DEAD);
						}
						hitMissText = "hits";
						attackerHitMissText = "hit";
						
					} else {
						hitMissText = "misses";
						attackerHitMissText = "miss";
					}
					atDesc.append("You " + weapon.getAttackVerb() + " at " + defender.getName() + " with your " + weapon.getName() + " and " + attackerHitMissText + "!");
					defDesc.append(actor.getName() + " " + weapon.getAttackVerb() + "s at YOU with " + hisHerText + " " + weapon.getName() + " and " + hitMissText + "!");
					onDesc.append(actor.getName() + " " + weapon.getAttackVerb() + "s at " + defender.getName() + " with " + hisHerText + " " + weapon.getName() + " and " + hitMissText + "!");
				} else {
					String hitMissText;
					String attackerHitMissText;
					if (roll >= 1) {
						hitMissText = "hits";
						attackerHitMissText = "hit";
					} else {
						hitMissText = "misses";
						attackerHitMissText = "miss";
					}
					atDesc.append("You attack " + defender.getName() + " and " + attackerHitMissText + "!");
					defDesc.append(actor.getName() + " attacks at YOU and " + hitMissText + "!");
					onDesc.append(actor.getName() + " attacks " + defender.getName() + " and " + hitMissText + "!");
					if (roll >= 1) {
						if (defender.getStatus() == GameCharacter.Status.HEALTHY) {
							defender.setStatus(GameCharacter.Status.HURT);
							defDesc.append("\nYou're hurt but still able to act normally.");
							atDesc.append("\n" + defender.getName() + " looks like " + hesShesText + " hurt.");
							onDesc.append("\n" + defender.getName() + " looks like " + hesShesText + " hurt.");
						} else if (defender.getStatus() == GameCharacter.Status.HURT) {
							defDesc.append("\nUnable to take anymore punishment, you fall to the ground, incapaticated.");
							atDesc.append("\n" + defender.getName() + " is unable to take anymore punishment and falls to the ground, incapaticated.");
							onDesc.append("\n" + defender.getName() + " is unable to take anymore punishment and falls to the ground, incapaticated.");
							defender.setStatus(GameCharacter.Status.INCAPACITATED);
						} else if (defender.getStatus() == GameCharacter.Status.INCAPACITATED) {
							defDesc.append("\nThat last vicious blow was all you could take. You die.The world slowly begins to fade and just as you take your final breath you see a white light. " +
									"The light grows brighter, and brighter but suddenly you see " + actor.getName() + "'s face and you feel a rage build up inside of you. You must have" +
									" vengance! Through sheer force of will you push yourself away from the light and suddenly find yourself back in the Inn, except at the front desk.");
							atDesc.append("\nThat final blow was all " + defender.getName() + " could take, " + hisHerText + " last breath escapes " + himHerText + " and " + heSheText + " dies. Now all that remains is their corpse.");
							onDesc.append("\nThat final blow was all " + defender.getName() + " could take, " + hisHerText + " last breath escapes " + himHerText + " and " + heSheText + " dies. Now all that remains is their corpse.");
							Body body = new Body(defender, "Looks like he got killed.");
							location.addBody(body);
							location.removeCharacter(defender);
							defender.setStatus(GameCharacter.Status.DEAD);
							Session defenderSession = Server.world.getSessionByCharacter(defender);
							Ghost ghost = new Ghost(defender.getName(), defender.getGender());
							Server.world.getArea(3).addCharacter(ghost);
							ghost.setLocation(Server.world.getArea(3));
							defenderSession.setCharacter(ghost);
							defender = ghost;
						}
					}
				}
				actionResponse.setActingCharacterDescription(atDesc.toString());
				actionResponse.addTargetCharacter(defender);
				actionResponse.setTargetCharacterDescription(defender, defDesc.toString());
				for (GameCharacter onlooker : location.getAreaOnlookers(actor, actionResponse.getTargetCharacters())) {
					actionResponse.addOnlooker(onlooker, onDesc.toString());
				}
				beginRecovery(actor, 3000);
			} else {
				actionResponse.setActingCharacterDescription("There is no one here by the name of " + param1 + " to attack.");
			}
			break;
		default:
			break;
		}
		return actionResponse;
	}

	public ActionResponse getActionResponse() {
		return actionResponse;
	}

	public Set<String> getKeywords() {
		return keywords;
	}
}